using System;
using System.Runtime.Serialization;
using System.Reflection;
using System.ComponentModel;
using System.Security.Permissions;
using System.Collections.Generic;

namespace SBPweb.Components
{
	/// <summary>
	/// Class of Component
	/// </summary>
	[Serializable]
	public class Component: System.ComponentModel.Component, IComponent
	{
		#region Private members

		private List<System.ComponentModel.IComponent> components;

		#endregion

		#region Constructor logic

		/// <summary>
		/// Constructor of Component
		/// </summary>
		public Component()
		{
		}

		/// <summary>
		/// Constructor of Component
		/// </summary>
		/// <param name="container">container of components</param>
		public Component(System.ComponentModel.IContainer container)
		{
            if (container == null)
            {
                throw new ArgumentNullException("container", "The parameter cannot be null");
            }
			container.Add(this);
		}

		/// <summary>
		/// Constructor of Component
		/// </summary>
		/// <param name="info">info about serialization</param>
		/// <param name="context">streaming context</param>
        protected Component(SerializationInfo info, StreamingContext context)
		{
			ResurrectObject(this, info/*, context - FxCop: Commented by LSzi*/);
		}

		#endregion

		#region Property accessors

		/// <summary>
		/// List of components
		/// </summary>
		public List<System.ComponentModel.IComponent> Components
		{
			get 
			{
				if (components == null)
				{
					Initialize();
				}
				return components;
			}
		}

		#endregion

		#region Events

		/// <summary>
		/// Raised when start to initialize
		/// </summary>
		public event CancelEventHandler Initializing;
		/// <summary>
		/// Raised when finished the initialization
		/// </summary>
		public event EventHandler Initialized;

		/// <summary>
		/// Raised when start to Terminate
		/// </summary>
		public event CancelEventHandler Terminating;
		/// <summary>
		/// Raised when finished the finalization
		/// </summary>
		public event EventHandler Terminated;

		#endregion

		#region Public methods

		/// <summary>
		/// Initialization
		/// </summary>
		/// <returns>success</returns>
		public bool Initialize()
		{
			if (Initializing != null)
			{
				CancelEventArgs cea = new CancelEventArgs(false);
				Initializing(this, cea);
				if (cea.Cancel)
				{
					return false;
				}
			}

			OnInitialize(this, EventArgs.Empty);

			if (Initialized != null)
			{
				Initialized(this, EventArgs.Empty);
			}

			return true;
		}

		/// <summary>
		/// Runs when initialized
		/// </summary>
		/// <param name="sender">sender</param>
		/// <param name="e">event argument</param>
		protected virtual void OnInitialize(object sender, EventArgs e)
		{
			components = new List<System.ComponentModel.IComponent>();
		}

		/// <summary>
		/// Finalization
		/// </summary>
		/// <returns>success</returns>
		public bool Terminate()
		{
			if (Terminating != null)
			{
				CancelEventArgs cea = new CancelEventArgs(false);
				Terminating(this, cea);
				if (cea.Cancel)
				{
					return false;
				}
			}

			OnTerminate(this, EventArgs.Empty);

			if (Terminated != null)
			{
				Terminated(this, EventArgs.Empty);
			}

			return true;
		}

		/// <summary>
		/// Runs when Terminated
		/// </summary>
		/// <param name="sender">sender</param>
		/// <param name="e">event argument</param>
		protected virtual void OnTerminate(object sender, EventArgs e)
		{
			foreach (System.ComponentModel.IComponent ic in Components)
			{
				if (ic is IComponent)
				{
					(ic as IComponent).Terminate();
				}
			}
		}

		/// <summary>
		/// Dispose
		/// </summary>
		/// <param name="disposing">disposing</param>
		protected override void Dispose(bool disposing)
		{
			if (Terminate())
			{
				base.Dispose(disposing);
			}
		}

		/// <summary>
		/// Get object data
		/// </summary>
		/// <param name="info">serialization info</param>
		/// <param name="context">streaming context</param>
        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
		public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
		{
            StoreObject(this, info/*, context - FxCop: Commented by LSzi*/);
		}

		#endregion

		#region Static helper methods

        internal static void ResurrectObject(object obj, SerializationInfo info/*, StreamingContext context - FxCop: Commented by LSzi*/)
		{
			Type type = obj.GetType();

			SerializationInfoEnumerator enu = info.GetEnumerator();
			while (enu.MoveNext())
			{
				object value = enu.Current.Value;

				FieldInfo fI = type.GetField(enu.Current.Name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
				if (fI != null)
				{
					fI.SetValue(obj, value);
					continue;
				}

				PropertyInfo pI = type.GetProperty(enu.Current.Name);
				if (pI != null && pI.CanWrite)
				{
					pI.SetValue(obj, value, null);
					continue;
				}
			}
		}

		internal static void StoreObject(object obj, SerializationInfo info/*, StreamingContext context - FxCop Commented by LSzi*/)
		{
			Type type = obj.GetType();

			foreach (FieldInfo fI in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
			{
				info.AddValue(fI.Name, fI.GetValue(obj));
			}

			foreach (PropertyInfo pI in type.GetProperties())
			{
				if (pI.CanRead && pI.PropertyType.IsSerializable)
				{
					info.AddValue(pI.Name, pI.GetValue(obj, null));
				}
			}

			info.SetType(obj.GetType());
		}

		#endregion

    }
}